package com.alingrad.android.froyoengine;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView;
import android.util.Log;

import com.alingrad.android.froyoengine.graphics.RenderNode;
import com.alingrad.android.froyoengine.util.FPSRecorder;
import com.alingrad.android.froyoengine.util.FixedSizeArray;
import com.alingrad.android.froyoengine.util.GLColor;

public class GameRenderer extends AllocationGuard implements GLSurfaceView.Renderer {
	public static final int MAX_RENDER_NODES = 256;
	
	public static int VIEW_WIDTH;
	public static int VIEW_HEIGHT;
	
	private Game mGame;
	
	private Object mListLock = new Object();
	private FixedSizeArray<RenderNode> mRenderList;
	private boolean mRenderListChanged;
	
	private Object mColorLock = new Object();
	private GLColor mColor;
	private boolean mColorChanged;
	
	private FPSRecorder mFPS;
	
	public GameRenderer(Game game) {
		super();
		mGame = game;
		mRenderList = new FixedSizeArray<RenderNode>(MAX_RENDER_NODES);
		mRenderListChanged = true;
		mFPS = new FPSRecorder();
	}
	
	public synchronized void updateList(FixedSizeArray<RenderNode> list) {
		synchronized (mListLock) {
			mRenderList = list;
			mRenderListChanged = true;
			mListLock.notify();
		}
	}
	
	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
		gl.glEnable(GL10.GL_DEPTH_TEST);
		gl.glShadeModel(GL10.GL_SMOOTH);
		
		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		gl.glDisable(GL10.GL_DITHER);
		gl.glDisable(GL10.GL_LIGHTING);
		gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
		
		gl.glClearColor(0f, 0f, .1f, 1f);
		mGame.load(this, gl);
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		VIEW_WIDTH = width;
		VIEW_HEIGHT = height;
		gl.glViewport(0, 0, width, height);
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glOrthof(0f, GameProperties.WIDTH, 0f, GameProperties.HEIGHT, 3f, 1000f);
		gl.glMatrixMode(GL10.GL_MODELVIEW);
	}
	
	int num = 0;

	@Override
	public void onDrawFrame(GL10 gl) {
		synchronized(mListLock) {
			if (!mRenderListChanged) {
				while (!mRenderListChanged) {
					try {
						mListLock.wait();
					} catch (InterruptedException ex) {
					}
				}
			}
			mRenderListChanged = false;
		}
		
		synchronized(mColorLock) {
			if (mColorChanged) {
				gl.glClearColor(mColor.getRed(), mColor.getGreen(), 
						mColor.getBlue(), mColor.getAlpha());
				mColorChanged = false;
			}
		}
		
		synchronized(this) {
			mFPS.update();
			gl.glLoadIdentity();
			gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

			for (int i = 0; i < mRenderList.size(); i++)
				mRenderList.get(i).draw(gl);
			if (num % 30 == 0) 
				Log.i(GameProperties.DEBUG_TAG, "FPS: " + mFPS.getAverage());
			num++;
		}
	}

	public void setBackgroundColor(GLColor color) {
		synchronized (mColorLock) {
			if (mColor != color) {
				mColor = color;
				mColorChanged = true;
			}
		}
	}
	
}